home *** CD-ROM | disk | FTP | other *** search
- /*
- * (c) Copyright 1992 by Panagiotis Tsirigotis
- * All rights reserved. The file named COPYRIGHT specifies the terms
- * and conditions for redistribution.
- */
-
- static char RCSid[] = "$Id: server.c,v 5.3 1992/11/17 06:34:06 panos Exp $" ;
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <syslog.h>
- #include <fcntl.h>
- #include <time.h>
-
- #include "fsma.h"
- #include "sio.h"
-
- #include "access.h"
- #include "connection.h"
- #include "config.h"
- #include "server.h"
- #include "state.h"
- #include "logoptions.h"
-
- #define server_free( serp ) fsm_free( server_allocator, (char *)serp )
-
-
- char *inet_ntoa() ;
- time_t time() ;
-
- void msg() ;
- void out_of_memory() ;
-
- static fsma_h server_allocator ;
-
-
- status_e server_init()
- {
- int flags = FSM_RETURN_ERROR ;
-
- #ifdef DEBUG
- flags |= FSM_ZERO_FREE ;
- #endif
- server_allocator = fsm_create( sizeof( struct server ), 0, flags ) ;
- return( ( server_allocator == NULL ) ? FAILED : OK ) ;
- }
-
-
-
- /*
- * Allocate a server, initialize it from init_serp, and insert it in stab
- */
- struct server *server_alloc( init_serp, stab )
- struct server *init_serp ;
- pset_h stab ;
- {
- register struct server *serp ;
- char *func = "server_alloc" ;
-
- serp = SERP( fsm_alloc( server_allocator ) ) ;
- if ( serp == NULL )
- {
- out_of_memory( func ) ;
- return( NULL ) ;
- }
-
- *serp = *init_serp ;
-
- if ( pset_add( stab, serp ) == NULL )
- {
- msg( LOG_CRIT, func, "couldn't insert server in server table" ) ;
- fsm_free( server_allocator, (char *) serp ) ;
- return( NULL ) ;
- }
-
- return( serp ) ;
- }
-
-
- status_e server_run( sp, cp )
- struct service *sp ;
- connection_s *cp ;
- {
- struct server server ;
- struct server *serp ;
- char *func = "server_run" ;
- status_e schedule_retry() ;
- void server_internal() ;
- void log_failure() ;
-
- CLEAR( server ) ;
- SERVER_SERVICE( &server ) = sp ;
- SERVER_CONNECTION( &server ) = cp ;
-
- /*
- * Allocate a server struct only if we will fork a new process
- */
- if ( ! SVC_FORKS( sp ) )
- {
- server_internal( &server ) ;
- return( OK ) ;
- }
-
- serp = server_alloc( &server, ps.rws.servers ) ;
- if ( serp == NULL )
- return( FAILED ) ;
-
- if ( server_start( serp ) == OK )
- {
- SVC_HOLD( sp ) ;
- return( OK ) ;
- }
-
- /*
- * Fork failed; remove the server from the server table
- */
- pset_remove( ps.rws.servers, serp ) ;
-
- /*
- * Currently, fork failures are the only reason for retrying.
- * There is no retry if we exceed the max allowed number of fork failures
- */
- if ( serp->fork_failures < MAX_FORK_FAILURES && SVC_RETRY( sp ) )
- {
- if ( schedule_retry( serp ) == OK )
- return( OK ) ;
- else
- msg( LOG_ERR, func, "Retry failure for %s service", CONF( sp )->id ) ;
- }
- else
- log_failure( AC_FORK, sp, cp ) ;
-
- server_free( serp ) ;
- return( FAILED ) ;
- }
-
-
- /*
- * If a service is internal and does not require forking a process:
- * - if it accepts connections, we put the accepted connection
- * in non-blocking mode to avoid a possible block on
- * the write(2).
- * - the log flags that have to do with the server exiting are
- * ignored (i.e. nothing is logged).
- * - it can be identified in the log because the server pid is 0.
- */
- PRIVATE void server_internal( serp )
- struct server *serp ;
- {
- register struct service *sp = SERVER_SERVICE( serp ) ;
- register struct service_config *scp = CONF( sp ) ;
- char *func = "server_internal" ;
- void log_success() ;
-
- serp->pid = 0 ;
- if ( ACCEPTS_CONNECTIONS( scp ) &&
- fcntl( SERVER_FD( serp ), F_SETFL, FNDELAY ) == -1 )
- msg( LOG_ERR, func, "%s: fcntl F_SETFL failed: %m", scp->id ) ;
- else
- {
- log_success( serp ) ;
- (*sp->builtin->function)( serp ) ;
- }
- }
-
-
- /*
- * Try to fork a server process
- */
- status_e server_start( serp )
- register struct server *serp ;
- {
- register struct service *sp = SERVER_SERVICE( serp ) ;
- register struct service_config *scp = CONF( sp ) ;
- char *func = "server_start" ;
- void child_process() ;
- void log_success() ;
-
- serp->log_remote_user = ( M_IS_SET( scp->log_on_success, LO_USERID ) &&
- ACCEPTS_CONNECTIONS( scp ) ) ;
- serp->pid = fork() ;
-
- switch ( serp->pid )
- {
- case 0:
- ps.rws.env_is_valid = FALSE ;
-
- child_process( serp ) ;
-
- msg( LOG_ERR, func, "child_process returned ???" ) ;
- _exit( 0 ) ;
- /* NOTREACHED */
-
- case -1:
- msg( LOG_ERR, func, "%s: fork failed: %m", scp->id ) ;
- serp->fork_failures++ ;
- return( FAILED ) ;
-
- default:
- (void) time( &serp->start_time ) ;
- SDATA( sp )->running_servers++ ;
-
- /*
- * Log the start of another server (if it is not an interceptor).
- * Determine if the server writes to the log (because in that case
- * we will have to check the log size).
- */
- if ( ! IS_INTERCEPTED( scp ) )
- log_success( serp ) ;
- else
- serp->writes_to_log =
- ( SVC_IS_LOGGING( SERVER_SERVICE( serp ) ) != NULL ) ;
- serp->writes_to_log |= serp->log_remote_user ;
- return( OK ) ;
- }
- }
-
-
- void server_release( serp )
- struct server *serp ;
- {
- struct service *sp = SERVER_SERVICE( serp ) ;
-
- if ( SVC_RELE( sp ) == 0 )
- pset_remove( SERVICES( ps ), sp ) ;
- else if ( IS_SUSPENDED( sp ) )
- svc_resume( sp ) ;
-
- server_free( serp ) ;
- }
-
-
- /*
- * This function is invoked on server exit if the service has installed it
- *
- * NOTE: In case of reconfiguration between server fork and exit, the
- * service attributes checked in this function may change.
- */
- void server_postmortem( serp )
- register struct server *serp ;
- {
- struct service *sp = SERVER_SERVICE( serp ) ;
- char *func = "server_postmortem" ;
- register struct service_config *scp = CONF( sp ) ;
- void log_exit() ;
-
- if ( SVC_IS_LOGGING( sp ) )
- {
- if ( serp->writes_to_log )
- {
- if ( debug.on )
- msg( LOG_DEBUG, func,
- "Checking log size of %s service", CONF( sp )->id ) ;
- xlog_control( SDATA( sp )->log_handle, XLOG_SIZECHECK ) ;
- }
-
- if ( M_IS_SET( scp->log_on_success, LO_DURATION ) ||
- M_IS_SET( scp->log_on_success, LO_EXIT ) )
- log_exit( serp ) ;
- }
-
- conn_free( SERVER_CONNECTION( serp ) ) ;
- }
-
-
-
- void server_dump( serp, fd )
- register struct server *serp ;
- int fd ;
- {
- Sprint( fd, "pid = %d\n", serp->pid ) ;
- Sprint( fd, "start_time = %s", ctime( &serp->start_time ) ) ;
- Sprint( fd, "sp = %p (service=%s)\n", SERVER_SERVICE( serp ),
- CONF( SERVER_SERVICE( serp ) )->id ) ;
- Sprint( fd, "Connection info:\n" ) ;
- conn_dump( SERVER_CONNECTION( serp ), fd ) ;
- Sprint( fd, "fork_failures = %d\n", serp->fork_failures ) ;
- Sprint( fd,
- "log_remote_user = %s\n", serp->log_remote_user ? "YES" : "NO" ) ;
- Sprint( fd, "writes_to_log = %s\n", serp->writes_to_log ? "YES" : "NO" ) ;
- Sputchar( fd, '\n' ) ;
- }
-
-
-